package cn.imokay.juc.lock;

import java.util.concurrent.TimeUnit;


/**
 * 面试题：为什么任何一个对象都能成为锁，
 * 浅析源码，所有对象继承自Object，Object上的一些方法还会在底层objectmonitor.cpp的c++源码中找到，会发现会初始化一个monitor对象，里面有个owner属性，记录持有该锁的线程
 *
 */

public class Lock8Demo {
    public static void main(String[] args) {

        lock4();

    }

    /**
     *同步普通方法，对象锁，同一个对象，能锁住所有同步普通方法，先call再sms
     */
    private static void lock1(){
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> phone.call()).start();
        try { TimeUnit.MILLISECONDS.sleep(200); } catch (Exception e) { e.printStackTrace();}
        new Thread(() -> phone.sms()).start();
    }

    /**
     *同步普通方法，对象锁，不同对象，无法锁住
     */
    private static void lock2(){
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> phone.call()).start();
        try { TimeUnit.MILLISECONDS.sleep(200); } catch (Exception e) { e.printStackTrace();}
        new Thread(() -> phone2.sms()).start();
    }

    /**
     * 同步普通方法和同步静态方法，锁对象不同，一个是对象实例，一个是类类的class对象，锁不住
     */
    public static void lock3(){
        Phone phone = new Phone();
        //Phone phone2 = new Phone();
        new Thread(() -> phone.call()).start();
        try { TimeUnit.MILLISECONDS.sleep(200); } catch (Exception e) { e.printStackTrace();}
        new Thread(() ->phone.email()).start();
    }

    /**
     * 两个静态同步方法，即使对象不同，也能锁住，因为锁对象是类的calss独享（全局唯一 ），其实java本身就不推荐通过对象来调用静态方法，推荐用类型直接调用
     */
    public static void lock4(){
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> phone2.internet()).start();
        try { TimeUnit.MILLISECONDS.sleep(200); } catch (Exception e) { e.printStackTrace();}
        new Thread(() ->phone.email()).start();
    }
}


/**
 * 资源类
 */

class Phone {
    public synchronized void call() {
        try {
            System.out.println("睡3秒");
            TimeUnit.SECONDS.sleep(3);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t---启动");
        System.out.println("call...");
    }

    public synchronized void sms() {
        System.out.println(Thread.currentThread().getName() + "\t---启动");
        System.out.println("sms...");
    }

    public static synchronized void email() {
        System.out.println(Thread.currentThread().getName() + "\t---启动");
        System.out.println("email...");
    }

    public static synchronized void internet() {
        System.out.println(Thread.currentThread().getName() + "\t---启动,睡一睡");
        try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace();}
        System.out.println("internet...");
    }
}


